﻿namespace Rally_MvvmC.Library
{
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using Newtonsoft.Json;
    using Rally_MvvmC.Exceptions;
    using Rally_MvvmC.ViewModels;

    public abstract class ViewControllerBase<DataStoreType> : ViewControllerBase
        where DataStoreType : IDataStore
    {
        [JsonIgnore]
        private DataStoreType dataStore;
        public DataStoreType DataStore
        {
            get
            {
                if (dataStore == null)
                {
                    dataStore = this.createDataStore();
                }

                return dataStore;
            }
        }

        protected virtual Func<DataStoreType> createDataStore
        {
            get
            {
                throw new NotImplementedException();
            }
        }
    }

    public abstract class ViewControllerBase : Controller
    {
        public virtual int userId { get; set; }

        public virtual string userName { get; set; }

        public string UserName
        {
            get
            {
                var userName = this.userName;
                if (string.IsNullOrWhiteSpace(userName))
                {
                    userName = this.PeekTemp<string>("UserName");
                }

                if (string.IsNullOrWhiteSpace(userName))
                {
                    userName = this.User.Identity.Name;
                }

                if (string.IsNullOrWhiteSpace(userName))
                {
                    userName = WebMatrix.WebData.WebSecurity.CurrentUserName;
                }

                this.PushTemp("UserName", userName);
                this.userName = userName;
                return userName;
            }

            set
            {
                this.PushTemp("UserName", value);
                this.userName = value;
            }
        }

        public int UserId
        {
            get
            {
                var userId = this.userId;
                if (userId <= 0)
                {
                    userId = this.PeekTempVal<int>("UserId");
                }

                if (userId <= 0)
                {
                    userId = WebMatrix.WebData.WebSecurity.GetUserId(this.User.Identity.Name);
                }

                this.PushTemp("UserId", userId);
                this.userId = userId;
                return userId;
            }

            set
            {
                this.PushTemp("UserId", value);
                this.userId = value;
            }
        }

        public virtual ActionResult PublishView()
        {
            return this.PublishView(null);
        }

        public virtual ActionResult PublishView(object model)
        {
            return this.PublishView(null, model);
        }

        public virtual ActionResult PublishView(string name, object model)
        {
            var pageModel = model as IPageViewModel;

            Response.Expires = pageModel.PageInfo.Expires;
            Response.Cache.SetAllowResponseInBrowserHistory(pageModel.PageInfo.SetAllowResponseInBrowserHistory);
            Response.CacheControl = pageModel.PageInfo.CacheControl;
            if (pageModel.PageInfo.SetNoServerCaching)
            {
                Response.Cache.SetNoServerCaching();
            }

            if (pageModel.PageInfo.SetNoStore)
            {
                Response.Cache.SetNoStore();
            }

            if (pageModel == null)
            {
                var routeName = Request.RawUrl;
                while (routeName.StartsWith("/"))
                {
                    routeName = routeName.Substring(1);
                }

                pageModel = new PageViewModelBase(routeName);
            }

            if (pageModel.IsAdministratorSite)
            {
                ViewBag.LayoutName = "Tools";
            }
            else if (!string.IsNullOrWhiteSpace(((PageViewModelBase)model).PageInfo.LayoutName))
            {
                ViewBag.LayoutName = ((PageViewModelBase)model).PageInfo.LayoutName;
            }

            if (Request.RawUrl.EndsWith("_"))
            {
                ViewBag.RenderPartial = true;

                if (!string.IsNullOrWhiteSpace(name))
                {
                    return this.View(name, model);
                }
                else if (model != null)
                {
                    return this.View(model);
                }
                else
                {
                    return this.View();
                }
            }
            else
            {
                //var url = name.Length == 0 || name.StartsWith("/") ? name : "/Views/" + name;
                if (!string.IsNullOrWhiteSpace(name) && name.IndexOf("/")==-1)
                {
                    return this.View(name, model);
                }
                else if (model != null)
                {
                    return this.View(model);
                }
                else
                {
                    return this.View();
                }
            }
        }

        protected override void OnActionExecuted(ActionExecutedContext ctx)
        {
            base.OnActionExecuted(ctx);
        }

        protected override void HandleUnknownAction(string actionName)
        {
            Response.Redirect("/Page/NotFound?aspxerrorpath=" + Request.Url.AbsoluteUri);
        }

        public static string GetUserIP(HttpContext HttpContext)
        {
            var ip = (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null && HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != string.Empty) ? HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] : HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
            if (ip.Contains(","))
            {
                return ip.Split(',').First().Trim();
            }

            return ip;
        }

        protected override void OnException(ExceptionContext filterContext)
        {
            Logger.LogException(filterContext.Exception);
            var model = new ErrorViewModel();

            model.HandleErrorInfo = new HandleErrorInfo(filterContext.Exception, filterContext.RequestContext.RouteData.Values["controller"].ToString(), filterContext.RequestContext.RouteData.Values["action"].ToString());
            var result = new ViewResult
            {
                ViewName = "Error",
                ViewData = new ViewDataDictionary<ErrorViewModel>(model),
                TempData = filterContext.Controller.TempData
            };

            filterContext.Result = result;
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 500;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }

        protected virtual void HandleException(Exception ex)
        {
            Logger.LogException(ex);
            this.PushTemp("Error", "Unexpected error.");
        }
    }
}
